// /*
//  * @Author: 杰编程 2306248989@qq.com
//  * @Date: 2023-07-20 11:28:26
//  * @LastEditors: 杰编程 2306248989@qq.com
//  * @LastEditTime: 2023-07-20 13:13:24
//  * @FilePath: /lesson16/shm/comm.hpp
//  * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
//  */

#ifndef __COMM_HPP__
#define __COMM_HPP__

#include<iostream>
using namespace std;

#include<cstring>
#include<cerrno>
#include<cassert>


#include<unistd.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<sys/stat.h>
#include<sys/fcntl.h>



#define PATHNAME "."
#define PROJID 0x6666

const size_t gsize=4096;

key_t GetKey()
{
    key_t key=ftok(PATHNAME,PROJID);
    if(key==-1)
    {
        cout<<"errno:"<<errno<<":"<<strerror(errno)<<endl;
        exit(1);
    }
    return key;
}

string toHex(int x)
{
    char buffer[64]={0};
    snprintf(buffer,sizeof(buffer),"0x%x",x);
    return buffer;
}

//  IPC_CREAT and IPC_EXCL
// 单独使用IPC_CREAT: 创建一个共享内存，如果共享内存不存在，就创建之，如果已经存在，获取已经存在的共享内存并返回
// IPC_EXCL不能单独使用，一般都要配合IPC_CREAT
// IPC_CREAT | IPC_EXCL: 创建一个共享内存，如果共享内存不存在，就创建之, 如果已经存在，则立马出错返回 -- 如果创建成功，对应的shm，一定是最新的！
static int CreateShmHelper(key_t key,size_t size,int shmflg)
{
    int shmid=shmget(key,gsize,shmflg);
    if(shmid==-1)
    {
        cerr<<"errno:"<<errno<<":"<<strerror(errno)<<endl;
        //  perror("shmget::");
        exit(2);
    }
    return shmid;
}

int CreateShm(key_t key)
{
    umask(0);
    return CreateShmHelper(key,gsize,IPC_CREAT|IPC_EXCL|0666);
}

int GetShm(key_t key)
{
    return CreateShmHelper(key,gsize,IPC_CREAT);
}


void DelShm(int shmid)
{
    int ret=shmctl(shmid,IPC_RMID,nullptr);
    if(ret==-1)
    {
        cerr<<"errno:"<<errno<<":"<<strerror(errno)<<endl;
        exit(3);
    }
}

char* attachShm(int shmid)
{
    char *start = (char*)shmat(shmid, nullptr, 0);
    return start;
}

void detachShm(char *start)
{
    int n = shmdt(start);
    assert(n != -1);
    (void)n;
}

#define SERVER 0
#define CLIENT 1

class init
{
public:
    init(int type)
    :_type(type)
    {
        key_t key=GetKey();
        if(type==CLIENT)
        {
            _shmid=CreateShm(key);
            cout<<"创建共享内存成功"<<endl;
        }
        else
        {
            _shmid=GetShm(key);
        }
        _start=attachShm(_shmid);
    }

    ~init()
    {
        detachShm(_start);
        if(_type==CLIENT)
        {
            DelShm(_shmid);
            cout<<"删除共享内存成功"<<endl;
        }
    }
    char* GetStart()
    {
        return _start;
    }

private:
    int _type;
    int _shmid;
    char *_start;
};


const string client_to_server="./1";
const string begin_task="yes";
mode_t mode=0666;


#endif
